package com.qixiaobao.nondirect.settle.service.impl;

import com.qixiaobao.common.core.domain.model.LoginUser;
import com.qixiaobao.common.enums.InsureFeeStatusEnum;
import com.qixiaobao.common.exception.UtilException;
import com.qixiaobao.common.utils.DateUtils;
import com.qixiaobao.common.utils.MybatisBatchUtils;
import com.qixiaobao.common.utils.SecurityUtils;
import com.qixiaobao.common.utils.StringUtils;
import com.qixiaobao.nondirect.invoice.domain.Bill;
import com.qixiaobao.nondirect.invoice.domain.BillInsureFee;
import com.qixiaobao.nondirect.invoice.mapper.BillInsureFeeMapper;
import com.qixiaobao.nondirect.invoice.mapper.BillMapper;
import com.qixiaobao.nondirect.settle.domain.InsureFee;
import com.qixiaobao.nondirect.settle.domain.InsureFeeCharge;
import com.qixiaobao.nondirect.settle.domain.dto.NonDirectWaitDTO;
import com.qixiaobao.nondirect.settle.domain.vo.NonDirectSettleWaitVO;
import com.qixiaobao.nondirect.settle.mapper.InsureFeeChargeMapper;
import com.qixiaobao.nondirect.settle.mapper.InsureFeeMapper;
import com.qixiaobao.nondirect.settle.mapper.NonDirectWaitMapper;
import com.qixiaobao.nondirect.settle.service.INonDirectWaitService;
import com.qixiaobao.nondirect.invoice.domain.domain.*;
import com.qixiaobao.system.domain.Dict;
import com.qixiaobao.system.domain.Person;
import com.qixiaobao.system.domain.SignCompany;
import com.qixiaobao.system.domain.SlaveUser;
import com.qixiaobao.system.domain.dto.CountDTO;
import com.qixiaobao.system.domain.dto.PersonDTO;
import com.qixiaobao.system.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @Description 非直接结算管理-待结算  业务层
 * @Author yangxm
 * @Date 2025/6/27 9:52
 */
@Slf4j
@Service
public class NonDirectWaitServiceImpl implements INonDirectWaitService {


    @Autowired
    private NonDirectWaitMapper nonDirectWaitMapper;
    @Autowired
    private DictMapper dictMapper;
    @Autowired
    private SlaveUserMapper slaveUserMapper;
    @Autowired
    private SignCompanyMapper signCompanyMapper;
    @Autowired
    private PersonMapper personMapper;
    @Autowired
    private ChargeMapper chargeMapper;
    @Autowired
    private InsureFeeMapper insureFeeMapper;
    @Autowired
    private BillMapper billMapper;
    @Autowired
    private BillInsureFeeMapper billInsureFeeMapper;


    /**
     * @Description 查询待结算列表
     * @Author yangxm
     * @Date 2025/6/27 9:52
     */
    @Override
    public List<NonDirectSettleWaitVO> selectWaitSettleList(NonDirectWaitDTO nonDirectWaitDTO) {
        log.info("查询非直接结算管理-待结算列表，参数：{}", nonDirectWaitDTO);
        long begin = System.currentTimeMillis();
        List<NonDirectSettleWaitVO> list = nonDirectWaitMapper.selectWaitSettleList(nonDirectWaitDTO);
        log.info("查询非直接结算管理-待结算sql，耗时：{}ms", System.currentTimeMillis() - begin);
        if (StringUtils.isNotEmpty(list)){
            List<Dict> dictList = dictMapper.selectDictList();
            Map<String, Map<String, String>> dictMap = new ConcurrentHashMap<>();
            if (StringUtils.isNotEmpty(dictList)) {
                dictMap = dictList.stream()
                        .filter(c -> c.getVal() != null)
                        .collect(Collectors.groupingBy(Dict::getType, Collectors.toMap(Dict::getK, Dict::getVal)));
            }
            Map<String, String> mealNameMap = dictMap.getOrDefault("mealname", Collections.emptyMap());
            Map<String, String> maimRatioMap = dictMap.getOrDefault("maimRatio", Collections.emptyMap());
            Map<String, String> insureperiodMap = dictMap.getOrDefault("insureperiod", Collections.emptyMap());
            Map<String, String> jobtypeMap = dictMap.getOrDefault("jobtype", Collections.emptyMap());
            Map<String, String> extensionMap = dictMap.getOrDefault("extension", Collections.emptyMap());

            //账号信息
            Map<Long, String> usernameMap = slaveUserMapper.selectUsernameList().stream()
                    .collect(Collectors.toMap(SlaveUser::getId, SlaveUser::getUsername));
            //付款单位
            Map<Long, String> payCompanyNameMap = signCompanyMapper.selectSignCompanyNameList().stream()
                    .collect(Collectors.toMap(SignCompany::getId, SignCompany::getCompanyName));

            Map<String, String> insureFromMap = new HashMap<>();
            insureFromMap.put("0", "增减员");
            insureFromMap.put("1", "投保");

            NonDirectSettleWaitVO nonDirectWaitVO;
            for (int i = 0; i < list.size(); i++) {
                nonDirectWaitVO = new NonDirectSettleWaitVO();
                nonDirectWaitVO.setPayCompanyName(payCompanyNameMap.getOrDefault(nonDirectWaitVO.getPayCompanyId(), ""));
                nonDirectWaitVO.setServiceName(usernameMap.getOrDefault(nonDirectWaitVO.getServiceId(), ""));
                nonDirectWaitVO.setMealNameVal(mealNameMap.getOrDefault(nonDirectWaitVO.getMealName(), ""));
                nonDirectWaitVO.setMaimRatioVal(maimRatioMap.getOrDefault(nonDirectWaitVO.getMaimRatio(), ""));
                nonDirectWaitVO.setExtensionVal(extensionMap.getOrDefault(nonDirectWaitVO.getExtension(), ""));
                nonDirectWaitVO.setJobTypeVal(jobtypeMap.getOrDefault(nonDirectWaitVO.getJobType(), ""));
                nonDirectWaitVO.setInsurePeriodVal(insureperiodMap.getOrDefault(nonDirectWaitVO.getInsurePeriod(), ""));
                nonDirectWaitVO.setSettlePerson("增员:" + nonDirectWaitVO.getAddNum() + ";减员:" + nonDirectWaitVO.getMinusNum());
                nonDirectWaitVO.setInsureFromVal(insureFromMap.get(nonDirectWaitVO.getInsureFrom()));
                nonDirectWaitVO.setAbandonFlagVal(nonDirectWaitVO.getAbandonFlag() == 1 ? "是" : "否");
                nonDirectWaitVO.setFinanceReckonVal(StringUtils.equals("0", nonDirectWaitVO.getFinanceReckon()) ? "否" : "是");
            }

        }
        log.info("查询非直接结算管理-待结算列表，总耗时：{}ms", System.currentTimeMillis() - begin);
        return list;
    }

    /**
     * @Description 直投结算管理-待结算 - 人员详情
     * @Author yangxm
     * @Date 2025/6/27 14:53
     * @param personDTO
     * @return java.util.List<com.qixiaobao.nondirect.invoice.domain.domain.Person>
     */
    @Override
    public List<Person> selectWaitSettlePersonList(PersonDTO personDTO) {
        return personMapper.selectChargePersonList(personDTO);
    }

    /**
     * @Description 待结算-结算人数和费用总计统计
     * @Author yangxm
     * @Date 2025/6/27 15:02
     * @param nonDirectWaitDTO
     * @return com.qixiaobao.nondirect.invoice.domain.domain.dto.CountDto
     */
    @Override
    public CountDTO selectWaitSettleTotal(NonDirectWaitDTO nonDirectWaitDTO) {
        return nonDirectWaitMapper.selectWaitSettleTotal(nonDirectWaitDTO);
    }

    /**
     * @Description 非直投结算管理-待结算 - 结算
     * @Author yangxm
     * @Date 2025/7/1 9:20
     * @param insureFee
     * @return int
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int settle(InsureFee insureFee) {
        log.info("非直投结算管理-待结算结算操作，参数：{}", insureFee);
        long begin = System.currentTimeMillis();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null){
            throw new UtilException("登录已失效，请重新登录！");
        }
        List<Long> supplyIdList = insureFee.getSupplyIdList();
        if (StringUtils.isEmpty(supplyIdList) || supplyIdList.size() != 1){
            throw new UtilException("参数：供应商不能为空且只能选择一个结算！");
        }
        insureFee.setSupplyId(supplyIdList.get(0));
        Long payCompanyId = insureFee.getPayCompanyId();
        if (payCompanyId == null){
            throw new UtilException("参数：付款公司不能为空！");
        }
        Long actualPayCompanyId = insureFee.getActualPayCompanyId();
        if (actualPayCompanyId == null){
            throw new UtilException("参数：实际付款公司不能为空！");
        }
        //付款类型校验
        if(StringUtils.isBlank(insureFee.getInsureFeePayType())){
            throw new UtilException("付款类型不能为空");
        }
        List<Long> chargeIdList = insureFee.getChargeIdList();
        if (StringUtils.isEmpty(chargeIdList)) {
            throw new UtilException("费用列表不能为空");
        }
        //根据费用ID集合查询费用结算状态
        List<String> insureFeeSettleList = chargeMapper.selectInsureFeeStatusListByIdList(chargeIdList);
        if (insureFeeSettleList == null || insureFeeSettleList.size() != chargeIdList.size()){
            throw new UtilException("数据已被操作，请刷新页面重新结算！");
        }
        //去重
        insureFeeSettleList = insureFeeSettleList.stream().distinct().collect(Collectors.toList());
        if (insureFeeSettleList.size() != 1 || !"0".equals(insureFeeSettleList.get(0))){
            throw new UtilException("有已经结算的费用，不能重复结算，请刷新页面重新结算！");
        }
        insureFee.setInsureFeeStatus(InsureFeeStatusEnum.WAIT_PAY.getCode());
        insureFee.setInsureFeeMonth(DateUtils.parseDateToStr(DateUtils.YYYY_MM, DateUtils.getNowDate()));
        if (StringUtils.isNotBlank(insureFee.getRemark())){
            insureFee.setRemarkOperator(loginUser.getUsername());
            insureFee.setRemarkTime(DateUtils.getNowDate());
        }

        //根据费用ID集合查询计算增员总人数、减员总人数、费用总计
        CountDTO countDTO = chargeMapper.selectChargeTotalByIdList(chargeIdList);
        //增员人数、减员人数、费用总计
        insureFee.setAddNum(countDTO.getCount());
        insureFee.setMinusNum(countDTO.getCount2());
        insureFee.setInsureFeeTotal(countDTO.getAmount());
        //若结算总金额为0则已开票
        if(BigDecimal.ZERO.compareTo(insureFee.getInsureFeeTotal()) == 0){
            insureFee.setInsureFeeStatus(InsureFeeStatusEnum.SETTLED.getCode());
        }
        //若实付保费为空，则取值费用总计
        if (insureFee.getActualInsureFee() == null){
            insureFee.setActualInsureFee(insureFee.getInsureFeeTotal());
        }
        //保存入库
        int row = insureFeeMapper.insertInsureFee(insureFee);
        //更新费用表中的结算状态
        chargeMapper.updateInsureFeeSettleByIdList("1", chargeIdList);

        //保存保单结算与费用 关联表
        InsureFeeCharge insureFeeCharge;
        List<InsureFeeCharge> insureFeeChargeList = new ArrayList<>();
        for (int i = 0; i < chargeIdList.size(); i++) {
            insureFeeCharge = new InsureFeeCharge();
            insureFeeCharge.setInsureFeeId(insureFee.getId());
            insureFeeCharge.setChargeId(chargeIdList.get(i));
            insureFeeChargeList.add(insureFeeCharge);
        }
        //中间表保存入库
        MybatisBatchUtils.batchUpdateOrInsert(insureFeeChargeList, InsureFeeChargeMapper.class, InsureFeeChargeMapper::insertInsureFeeCharge);
        //结算总金额为0则已开票
        if(BigDecimal.ZERO.compareTo(insureFee.getInsureFeeTotal()) == 0){
            Bill bill=new Bill();
            bill.setSupplyId(insureFee.getSupplyId());
            bill.setPayCompanyId(insureFee.getActualPayCompanyId());
            bill.setAddNum(insureFee.getAddNum());
            bill.setMinusNum(insureFee.getMinusNum());
            bill.setInsureFeeTotal(insureFee.getInsureFeeTotal());
            bill.setBillStatus("1");
            billMapper.insertBill(bill);
            BillInsureFee billInsureFee=new BillInsureFee();
            billInsureFee.setBillId(bill.getId());
            billInsureFee.setInsureFeeId(insureFee.getId());
            billInsureFeeMapper.insertBillInsureFee(billInsureFee);
        }
        log.info("非直投结算管理-待结算结算操作，总耗时：{}ms", System.currentTimeMillis() - begin);
        return row;
    }

    /**
     * @Description 非直投结算管理-待结算 - 一键结算
     * @Author yangxm
     * @Date 2025/7/1 9:23
     * @param nonDirectWaitDTO
     * @return int
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int settleAll(NonDirectWaitDTO nonDirectWaitDTO) {
        log.info("非直投结算管理-待结算 - 一键结算，参数：{}", nonDirectWaitDTO);
        long begin = System.currentTimeMillis();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null){
            throw new UtilException("登录已失效，请重新登录！");
        }
        if (StringUtils.isEmpty(nonDirectWaitDTO.getSupplyIdList()) || nonDirectWaitDTO.getSupplyIdList().size() != 1){
            throw new UtilException("参数：供应商不能为空且只能选择一个结算！");
        }
        if (nonDirectWaitDTO.getPayCompanyId() == null){
            throw new UtilException("参数：付款公司不能为空！");
        }
        if (nonDirectWaitDTO.getActualPayCompanyId() == null){
            throw new UtilException("参数：实际付款公司不能为空！");
        }
        if (nonDirectWaitDTO.getInsureFeePayType() == null){
            throw new UtilException("参数：付款类型不能为空！");
        }
        //根据条件查询需要结算的数据集合
        List<NonDirectSettleWaitVO> list = nonDirectWaitMapper.selectWaitSettleList(nonDirectWaitDTO);;
        if (StringUtils.isEmpty(list)){
            throw new UtilException("没有可结算的数据！");
        }
        //需要结算的费用id集合
        List<Long> chargeIdList = list.stream().map(NonDirectSettleWaitVO::getChargeId).collect(Collectors.toList());
        //封装保费结算数据
        InsureFee insureFee = new InsureFee();
        insureFee.setSupplyIdList(nonDirectWaitDTO.getSupplyIdList());
        insureFee.setPayCompanyId(nonDirectWaitDTO.getPayCompanyId());
        insureFee.setActualPayCompanyId(nonDirectWaitDTO.getActualPayCompanyId());
        insureFee.setActualInsureFee(nonDirectWaitDTO.getActualInsureFee());
        insureFee.setInsureFeePayType(nonDirectWaitDTO.getInsureFeePayType());
        insureFee.setRemark(nonDirectWaitDTO.getRemark());
        insureFee.setChargeIdList(chargeIdList);
        int row = settle(insureFee);
        log.info("非直投结算管理-待结算 - 一键结算，总耗时：{}ms", System.currentTimeMillis() - begin);
        return row;
    }
}
